#include "Model.h"


float Abs(float f)
{
  if (f < 0)
    return -f;
  return f;
}

float Max(float x, float y) 
{
  if (y > x)
    return y;
  return x;
}


Model::Model()
{
	m_TotalConnectedTriangles = 0; 
	m_TotalConnectedPoints = 0;

}

Model::~Model()
{

}

int Model::Load(char* filename)
{
	string line;
	ifstream objFile (filename);	
	if (objFile.is_open())													// If obj file is open, continue
	{
		objFile.seekg (0, ios::end);										// Go to end of the file, 
		long fileSize = objFile.tellg();									// get file size
		objFile.seekg (0, ios::beg);										// we'll use this to register memory for our 3d model
 
		m_vertexBuffer = (float*) malloc (fileSize);							// Allocate memory for the verteces
		m_Faces_Triangles = (float*) malloc(fileSize*sizeof(float));			// Allocate memory for the triangles
		m_normals  = (float*) malloc(fileSize*sizeof(float));					// Allocate memory for the m_normals
 
		int triangle_index = 0;												// Set triangle index to zero
		int normal_index = 0;												// Set normal index to zero
 
		while (! objFile.eof() )											// Start reading file data
		{		
			getline (objFile,line);											// Get line from file
 
			if (line.c_str()[0] == 'v')										// The first character is a v: on this line is a vertex stored.
			{
				line[0] = ' ';												// Set first character to 0. This will allow us to use sscanf
 
				sscanf(line.c_str(),"%f %f %f ",							// Read floats from the line: v X Y Z
					&m_vertexBuffer[m_TotalConnectedPoints],
					&m_vertexBuffer[m_TotalConnectedPoints+1], 
					&m_vertexBuffer[m_TotalConnectedPoints+2]);


				//Elaborate testing system of uselesness
				//float* tempArr = new float[3];

				//for (int i = 0; i < 2; ++i)
				//{
				//	tempArr[i] = 0.0f;
				//}

				//sscanf(line.c_str(),"%f %f %f ",							// Read floats from the line: v X Y Z
				//	&tempArr[m_TotalConnectedPoints],
				//	&tempArr[m_TotalConnectedPoints+1], 
				//	&tempArr[m_TotalConnectedPoints+2]);

				//for (int i = 0; i < 3; ++i)
				//{
				//	DEBUGVERTEXVEC.push_back(&tempArr[i]);
				//}
				//DEBUGVERTEXVEC;
				// woololooo
 
				m_TotalConnectedPoints += POINTS_PER_VERTEX;					// Add 3 to the total connected points
			}
			if (line.c_str()[0] == 'f')										// The first character is an 'f': on this line is a point stored
			{
		    	line[0] = ' ';												// Set first character to 0. This will allow us to use sscanf
 
				int vertexNumber[4] = { 0, 0, 0 };
                sscanf(line.c_str(),"%i%i%i",								// Read integers from the line:  f 1 2 3
					&vertexNumber[0],										// First point of our triangle. This is an 
					&vertexNumber[1],										// pointer to our vertexBuffer list
					&vertexNumber[2] );										// each point represents an X,Y,Z.
 
				vertexNumber[0] -= 1;										// OBJ file starts counting from 1
				vertexNumber[1] -= 1;										// OBJ file starts counting from 1
				vertexNumber[2] -= 1;										// OBJ file starts counting from 1
 
 
				/********************************************************************
				 * Create triangles (f 1 2 3) from points: (v X Y Z) (v X Y Z) (v X Y Z). 
				 * The vertexBuffer contains all verteces
				 * The triangles will be created using the verteces we read previously
				 */
 
				int tCounter = 0;
				for (int i = 0; i < POINTS_PER_VERTEX; i++)					
				{
					m_Faces_Triangles[triangle_index + tCounter   ] = m_vertexBuffer[3*vertexNumber[i] ];
					m_Faces_Triangles[triangle_index + tCounter +1 ] = m_vertexBuffer[3*vertexNumber[i]+1 ];
					m_Faces_Triangles[triangle_index + tCounter +2 ] = m_vertexBuffer[3*vertexNumber[i]+2 ];
					tCounter += POINTS_PER_VERTEX;
				}
 
				/*********************************************************************
				 * Calculate all m_normals, used for lighting
				 */ 
				float coord1[3] = { m_Faces_Triangles[triangle_index], m_Faces_Triangles[triangle_index+1],m_Faces_Triangles[triangle_index+2]};
				float coord2[3] = {m_Faces_Triangles[triangle_index+3],m_Faces_Triangles[triangle_index+4],m_Faces_Triangles[triangle_index+5]};
				float coord3[3] = {m_Faces_Triangles[triangle_index+6],m_Faces_Triangles[triangle_index+7],m_Faces_Triangles[triangle_index+8]};
				float *norm = this->CalculateNormal( coord1, coord2, coord3 );
 
				tCounter = 0;
				for (int i = 0; i < POINTS_PER_VERTEX; i++)
				{
					m_normals[normal_index + tCounter ] = norm[0];
					m_normals[normal_index + tCounter +1] = norm[1];
					m_normals[normal_index + tCounter +2] = norm[2];
					tCounter += POINTS_PER_VERTEX;
				}
 
				triangle_index += TOTAL_FLOATS_IN_TRIANGLE;
				normal_index += TOTAL_FLOATS_IN_TRIANGLE;
				m_TotalConnectedTriangles += TOTAL_FLOATS_IN_TRIANGLE;			
			}	
		}
		objFile.close();														// Close OBJ file
	}
	else 
	{
		cout << "Unable to open file";								
	}
	return 0;

	//Unitize();
}
 
void Model::Release()
{
	free(this->m_Faces_Triangles);
	free(this->m_normals);
	free(this->m_vertexBuffer);
}

float* Model::CalculateNormal( float *coord1, float *coord2, float *coord3 )
{
   /* calculate Vector1 and Vector2 */
   float va[3], vb[3], vr[3], val;
   va[0] = coord1[0] - coord2[0];
   va[1] = coord1[1] - coord2[1];
   va[2] = coord1[2] - coord2[2];
 
   vb[0] = coord1[0] - coord3[0];
   vb[1] = coord1[1] - coord3[1];
   vb[2] = coord1[2] - coord3[2];
 
   /* cross product */
   vr[0] = va[1] * vb[2] - vb[1] * va[2];
   vr[1] = vb[0] * va[2] - va[0] * vb[2];
   vr[2] = va[0] * vb[1] - vb[0] * va[1];
 
   /* normalization factor */
   val = sqrt( vr[0]*vr[0] + vr[1]*vr[1] + vr[2]*vr[2] );
 
	float norm[3];
	norm[0] = vr[0]/val;
	norm[1] = vr[1]/val;
	norm[2] = vr[2]/val;
 
 
	return norm;
}

void Model::Draw()
{
 	glEnableClientState(GL_VERTEX_ARRAY);						// Enable vertex arrays
 	glEnableClientState(GL_NORMAL_ARRAY);						// Enable normal arrays
	glVertexPointer(3,GL_FLOAT,	0,m_Faces_Triangles);				// Vertex Pointer to triangle array
	glNormalPointer(GL_FLOAT, 0, m_normals);						// Normal pointer to normal array
	glDrawArrays(GL_TRIANGLES, 0, m_TotalConnectedTriangles);		// Draw the triangles
	glDisableClientState(GL_VERTEX_ARRAY);						// Disable vertex arrays
	glDisableClientState(GL_NORMAL_ARRAY);						// Disable normal arrays		

	//	glGenBuffersARB(2,m_BufferID);

	//glVertexPointer(3,GL_FLOAT,	0,m_Faces_Triangles);

	////Vertex Buffer
	//glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_BufferID[VERTEX]);
	//glBufferDataARB(GL_ARRAY_BUFFER_ARB,
	//	m_TotalConnectedPoints * 3 * sizeof(GLfloat),m_vertexBuffer, GL_STATIC_DRAW_ARB);

	////Indice Buffer
	///*glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,m_BufferID[INDEX]);
	//	glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
	//	m_pModel->numIndices * 3 * sizeof(GLfloat),m_pModel->indexList, GL_STATIC_DRAW_ARB);
	//	*/



	//glEnableClientState(GL_VERTEX_ARRAY);

	//glDrawArrays(GL_TRIANGLES, 0, m_TotalConnectedTriangles);

	//glDisableClientState(GL_VERTEX_ARRAY);

	//glBegin(GL_TRIANGLES);
	//for (int i = 0; i < m_TotalConnectedPoints; i += POINTS_PER_VERTEX)
	//{

	//	float x,y,z;
	//	x = m_vertexBuffer[i];
	//	y = m_vertexBuffer[i+1];
	//	z = m_vertexBuffer[i+2];
	//	glVertex3f(x,y,z);
	//}
	//glEnd();
}

void Model::Unitize()
{
  GLuint  i;
  GLfloat maxx, minx, maxy, miny, maxz, minz;
  GLfloat cx, cy, cz, w, h, d;
  GLfloat scale;

  /* get the max/mins */
  maxx = minx = m_vertexBuffer[3 + 0];
  maxy = miny = m_vertexBuffer[3 + 1];
  maxz = minz = m_vertexBuffer[3 + 2];
  for (i = 1; i <= m_TotalConnectedPoints; i++) {
    if (maxx < m_vertexBuffer[3 * i + 0])
      maxx = m_vertexBuffer[3 * i + 0];
    if (minx > m_vertexBuffer[3 * i + 0])
      minx = m_vertexBuffer[3 * i + 0];

    if (maxy < m_vertexBuffer[3 * i + 1])
      maxy = m_vertexBuffer[3 * i + 1];
    if (miny > m_vertexBuffer[3 * i + 1])
      miny = m_vertexBuffer[3 * i + 1];

    if (maxz < m_vertexBuffer[3 * i + 2])
      maxz = m_vertexBuffer[3 * i + 2];
    if (minz > m_vertexBuffer[3 * i + 2])
      minz = m_vertexBuffer[3 * i + 2];
  }

  /* calculate model width, height, and depth */
  w = Abs(maxx) + Abs(minx);
  h = Abs(maxy) + Abs(miny);
  d = Abs(maxz) + Abs(minz);

  /* calculate center of the model */
  cx = (maxx + minx) / 2.0;
  cy = (maxy + miny) / 2.0;
  cz = (maxz + minz) / 2.0;

  /* calculate unitizing scale factor */
  scale = 2.0 / Max(Max(w, h), d);

  /* translate around center then scale */
  for (i = 1; i <= m_TotalConnectedPoints; i++) {
    m_vertexBuffer[3 * i + 0] -= cx;
    m_vertexBuffer[3 * i + 1] -= cy;
    m_vertexBuffer[3 * i + 2] -= cz;
    m_vertexBuffer[3 * i + 0] *= scale;
    m_vertexBuffer[3 * i + 1] *= scale;
    m_vertexBuffer[3 * i + 2] *= scale;
  
  }
}

//void Model::Init(char* filename)
//{   
//	if (!m_pModel) 
//	{
//		m_pModel = glmReadOBJ(filename);
//		if (!m_pModel) exit(0);
//		glmUnitize(m_pModel);
//	}
//	glmDraw(m_pModel,GLM_SMOOTH);
//}
//
//void Model::Draw()
//{
//	//memcpy( indexedVertices, m_pModel->indexedvertexlist.begin(), sizeof( GLfloat ) * count );
//
//	glGenBuffersARB(2,m_BufferID);
//
//	//Vertex Buffer
//	glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_BufferID[VERTEX]);
//	glBufferDataARB(GL_ARRAY_BUFFER_ARB,
//		m_pModel->numvertices * 3 * sizeof(GLfloat),m_pModel->vertices, GL_STATIC_DRAW_ARB);
//
//	//Indice Buffer
//	/*glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,m_BufferID[INDEX]);
//		glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
//		m_pModel->numIndices * 3 * sizeof(GLfloat),m_pModel->indexList, GL_STATIC_DRAW_ARB);
//		*/
//	glVertexPointer(3,GL_FLOAT,0,(char*)NULL);
//
//
//
//	glEnableClientState(GL_VERTEX_ARRAY);
//
//	glDrawArrays(GL_TRIANGLES, 0, m_pModel->numvertices);
//
//	glDisableClientState(GL_VERTEX_ARRAY);
//
//}